#!/bin/sh

ENV_DUMP_FILE="/tmp/environment"
refresh_env_dump() {
	# sanitize and dump environment variables
	fw_printenv | sort | \
		sed -E 's/([`"$])/\\\1/g' | \
		sed -E 's/=(.*)$/="\1"/' \
		> "$ENV_DUMP_FILE"
}
if [ ! -f "$ENV_DUMP_FILE" ]; then
	refresh_env_dump
fi
. "$ENV_DUMP_FILE"

CONFIG_FILE="/etc/thingino.config"
if [ -f "$CONFIG_FILE" ]; then
#	echo "Evaluating $CONFIG_FILE" >&2
	. "$CONFIG_FILE"
fi

PID=$$

CRONTABS="/etc/cron/crontabs/root"
CURL="curl --show-error --fail --connect-timeout 10 --max-time 30 --retry 3 --location --max-redirs 5"
EMAIL_FORMAT='^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
HOSTNAME_FILE="/etc/hostname"
HOSTS_FILE="/etc/hosts"
LOG_FILE="/tmp/webui.log"
LOG_SIZE_LIMIT=50000
NTP_DEFAULT_FILE="/etc/default/ntp.conf"
NTP_WORKING_FILE="/tmp/ntp.conf"
OS_RELEASE_FILE="/etc/os-release"
PORTAL_MODE_FLAG="/run/portal_mode"
RESOLV_DEFAULT_FILE="/etc/default/resolv.conf"
RESOLV_FILE="/etc/resolv.conf"
RESOLV_WORKING_FILE="/tmp/resolv.conf"
SNAPSHOT_FILE="/tmp/snapshot.jpg"
SOC_FAMILY=$(soc -f)
SOC_MODEL=$(soc -m)
TZCODE_FILE="/etc/TZ"
TZJSON_FILE="/usr/share/tz.json"
TZNAME_FILE="/etc/timezone"
VBUFFER_FILE="/tmp/vbuffer.mp4"
WLANAP_MODE_FLAG="/run/wlanap_mode"

DAEMON=${DAEMON:-$0}
DAEMON_ARGS=${DAEMON_ARGS:-}
DAEMON_PATH="/bin"
DAEMON_SHORT=$(basename "${DAEMON%% *}" | sed -r 's/^[FKS][0-9][0-9]//')
DAEMON_FULL="$(which $DAEMON_SHORT)"
LOCK_FILE="/run/process-$PID.pid"
PIDFILE="/run/$DAEMON_SHORT.pid"

DAEMON_CONFIG="/etc/default/$DAEMON_SHORT"
if [ -r "$DAEMON_CONFIG" ]; then
#	echo "Evaluating $DAEMON_CONFIG" >&2
	. "$DAEMON_CONFIG"
fi

# test cases:
# network={
#        ssid="ssid"
#        #psk="`1234567890-=qwertyuiop[]asdfghjkl;'zxcvbnm,./"
#        psk=2bc720c7bab24823e4b6ce3150ef1fcfee08a12f0be79f0352f7933bec8c53c5
# }
# network={
#        ssid="ssid"
#        #psk="~!@#$%^&*()_+QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?"
#        psk=9268459e6347c6993772adedafd17a15b603c7232d80e91cab14585cfca3caf1
# }

# convert plain-text password to psd

convert_psk() {
	local psk tmpfile

	if [ ${#2} -ge 64 ]; then
		echo "$2"
	else
		tmpfile="/tmp/bogus.wpa"
		wpa_passphrase "$1" "$2" > $tmpfile
		psk=$(grep '^\s*psk=' $tmpfile | cut -d= -f2 | tail -n 1)
		rm -f $tmpfile
		echo "$psk"
	fi
}

decrement_mac() {
	local mac last_byte_dec

	mac=$ethaddr
	if [ -z "$mac" ]; then
		echo_error "Error: MAC address not found in $CONFIG_FILE"
		exit 1
	fi

	last_byte_dec=$((0x${mac##*:} - 1))
	if [ $last_byte_dec -lt 0 ]; then
		echo_error "Error: MAC address cannot be decremented below 00"
		exit 1
	fi

	ethaddr=$(printf "%s:%02x" "${mac%:*}" "$last_byte_dec")
}

die() {
	echo "$1" >&2
	exit 1
}

echo_command() {
	echo -e "\e[38;5;101m  $1\e[0m" >&2
}

echo_error() {
	echo -e "\e[38;5;160m  $1\e[0m" >&2
}

echo_info() {
	echo -e "\e[38;5;240m- $1\e[0m" >&2
}

echo_title() {
	echo -e "\e[38;5;015m$1 ...\e[0m" >&2
}

echo_warning() {
	echo -e "\e[38;5;142m  $1\e[0m" >&2
}

ensure_command() {
	if ! command -v "$1" > /dev/null; then
		echo_error "Missing $1"
		exit 1
	fi
}

ensure_dir() {
	if [ -d "$1" ]; then
		echo_info "Directory $1 exists"
		return 0
	fi

	if ! mkdir -p "$1"; then
		echo_error "Cannot create directory $1"
	fi

	if [ ! -w "$1" ]; then
		echo_error "Cannot write to $1"
	fi
}

gpio_control() {
	gpio_name="$1"
	gpio_power="$(grep ^${gpio_name}= $CONFIG_FILE | cut -d= -f2)"

	if [ -z "$gpio_power" ]; then
		return 1  # no value
	fi

	num=${gpio_power%[oO]}
	state=${gpio_power#$num}

	case "$state" in
		O)
			gpio_cmd="high"
			;;
		o)
			gpio_cmd="low"
			;;
		*)
			echo_warning "Invalid state for GPIO $gpio_name: $state"
			return 2  # invalid state
			;;
	esac

	echo_info "Set GPIO $num $gpio_cmd"
	gpio $gpio_cmd $num 2>&1 && return 0  # success

	echo_warning "Failed to set GPIO $num $gpio_cmd"
	return 3  # failure
}

iface_default() {
	local iface

	[ -z "$iface" ] && iface=$(ip -4 r | awk '/default/{print $5; exit}')
	[ -z "$iface" ] && iface=$(ip -4 r | awk '{print $3; exit}')
	[ -z "$iface" ] && iface=$(ip -6 r | awk '/default/{print $5; exit}')
	[ -z "$iface" ] && iface=$(ip -6 r | awk '{print $3; exit}')

	# to stdout
	echo "$iface"
}

iface_default2() {
	ipv4_iface=$(ip -4 r | sed -nE '/default/s/.+dev (\w+).+?/\1/p' | head -n 1)
	if [ -n "$ipv4_iface" ]; then
		# to stdout
		echo "$ipv4_iface"
	else
		ip -6 r | sed -nE '/default/s/.+dev (\w+).+?/\1/p' | head -n 1
	fi
}

iface_exists() {
	iface="$1"

	if [ -z "$iface" ]; then
		echo_warning "Interface parameter missing."
		return 1
	fi

	if ip link show $iface &> /dev/null; then
		if [ "eth0" = $iface ] && ! is_gateway_reachable; then
			echo_warning "eth0 has no local connection"
			return 1
		fi

		# echo_info "Interface '$iface' exists." >&2
		return 0
	else
		echo_warning "Interface '$iface' does not exist."
		return 1
	fi
}

iface_mac_suffix() {
	#ip link show $1 | awk '/ether/ {print $2}' | sed -E 's/://g;s/.*(.{4})$/\1/'
	ip link show $1 | awk '/ether/ {print $2}' | awk -F: '{print $(NF-1) $NF}'
}

is_debug_mode() {
	[ "0$((debug))" -gt 0 ] || [ "true" = "$debug" ]
}

is_streamer_disabled() {
	[ "true" = "$disable_streamer" ] || [ -f /run/portal_mode ]
}

is_streamer_running() {
	pidof prudynt > /dev/null
}

is_gateway_reachable() {
	[ -z "$iface" ] && return 1
	ping -c 1 -W 1 -I $iface $(ip -4 route | grep $iface | grep default | awk '{print $3}') > /dev/null 2>&1 || \
	ping -6 -c 1 -W 1 -I $iface $(ip -6 route | grep $iface | grep default | awk '{print $3}') > /dev/null 2>&1
}

log() {
	logger -p daemon.info -t ${DAEMON_SHORT}[$$] <&0
}

print_release() {
	if [ ! -f "$OS_RELEASE_FILE" ]; then
		echo_warning "$OS_RELEASE_FILE not found"
		return 1
	fi

	. "$OS_RELEASE_FILE"

	# to stdout
	echo_c 208 "Thingino $IMAGE_ID [$BUILD_ID]\n"
	echo "Thingino $IMAGE_ID [$BUILD_ID]"
}

quit() {
	echo "$1" >&2
	exit 0
}

set_gpio() {
	echo_info "Set GPIO $1 to F$2 D$3"
	gpio-diag $1 func $2 drive $3
}

singleton() {
	if [ -z "$1" ]; then
		echo_error "Program name is missing"
		exit 1
	fi

	local appname

	appname=$(basename $1)
	pids=$(pidof -o %PPID $appname)
	if [ -n "$pids" ]; then
		echo_error "$appname is already running with PIDs $pids. Exiting"
		exit 1
	fi
}

start_daemon() {
	local command

	command="${COMMAND:-$DAEMON_FULL} -- $DAEMON_ARGS"
	echo_command "$command"
	if [ -n "$PIDFILE" ] && [ -f "$PIDFILE" ]; then
		start-stop-daemon -b -S -m -p $PIDFILE -x $command 2>&1
	else
		start-stop-daemon -b -S -x $command 2>&1
	fi
}

starting() {
	echo "Starting ${1:-$DAEMON_SHORT}..."
}

stop_daemon() {
	if [ -f "$PIDFILE" ]; then
		echo "- Stopping $DAEMON_SHORT by PID from $PIDFILE"
		start-stop-daemon -K -p $PIDFILE
		[ -f "$PIDFILE" ] && rm "$PIDFILE"
	fi

	sleep 0.2
	if pidof $DAEMON_SHORT > /dev/null; then
		echo "- Killing $DAEMON_SHORT by PID"
		start-stop-daemon -K -n $DAEMON_SHORT
	fi

	sleep 0.2
	if pidof $DAEMON_SHORT > /dev/null; then
		echo "- Killing $DAEMON_SHORT by name"
		start-stop-daemon -K -s SIGKILL -n $DAEMON_SHORT
	fi
	sleep 0.2
	if pidof $DAEMON_SHORT > /dev/null; then
		echo "- Killing $DAEMON_SHORT by full process name $DAEMON_FULL"
		start-stop-daemon -K -x $DAEMON_FULL
	fi
}

stopping() {
	echo "Stopping ${1:-$DAEMON_SHORT}..."
}

tag() {
	echo "$(ts) [$PID:$plugin]"
}

ts() {
	date -u +"%F %T"
}

get_terminal_height() {
	# Try multiple methods to get terminal height
	height=""

	# Method 1: stty size (most reliable in busybox/ash)
	if command -v stty >/dev/null 2>&1; then
		height=$(stty size 2>/dev/null | cut -d' ' -f1)
	fi

	# Method 2: tput lines (if available)
	if [ -z "$height" ] && command -v tput >/dev/null 2>&1; then
		height=$(tput lines 2>/dev/null)
	fi

	# Method 3: environment variable
	if [ -z "$height" ] && [ -n "$LINES" ]; then
		height=$LINES
	fi

	# Method 4: ttysize command (busybox)
	if [ -z "$height" ] && command -v ttysize >/dev/null 2>&1; then
		height=$(ttysize h 2>/dev/null)
	fi

	# Default fallback
	if [ -z "$height" ] || [ "$height" -lt 10 ]; then
		height=24
	fi

	echo "$height"
}

usage() {
	# {start|stop|restart|status}
	echo "Usage: $0 $1" >&2
	exit 1
}
